{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit NavigationManager;

interface

uses Classes, Windows, Mediate_TLB;

const
  FILE_NAVIGATION = 'Navigation.xml';
  APP_CUSTOM  = 'Custom Application';
  APP_IGUIDE3 = 'iNav iGuidance 3.0';
  APP_PC_NAV6 = 'Directions Ltd. PC Navigator 6';
  APP_PC_NAV7 = 'Directions Ltd. PC Navigator 7';

type
  TAHMNavigationManager = class;

  TAHMNavigationApplication = class(TPersistent)
  private
    FName: WideString;
    FReadOnly: Boolean;
    FPath: WideString;
    FParameters: WideString;
    FWindowName: WideString;
    FWindowClass: WideString;
    FWindowLock: Boolean;
  protected
  public
    procedure Clear;
    procedure Assign(Source: TPersistent); override;
  published
    property Name: WideString read FName write FName;
    property ReadOnly: Boolean read FReadOnly write FReadOnly;
    property Path: WideString read FPath write FPath;
    property Parameters: WideString read FParameters write FParameters;
    property WindowName: WideString read FWindowName write FWindowName;
    property WindowClass: WideString read FWindowClass write FWindowClass;
    property WindowLock: Boolean read FWindowLock write FWindowLock;
  end;

  TAHMNavigationApplications = class
  private
    FList: TList;
  protected
    function GetCount: Integer;
    function GetApplication(Index: Integer): TAHMNavigationApplication;
    function AddApplication(Name, Path, WindowName, WindowClass: WideString; WindowLock: Boolean): TAHMNavigationApplication;
    procedure Clear;
  public
    constructor Create;
    destructor Destroy; override;
    property Count: Integer read GetCount;
    property Applications[Index: Integer]: TAHMNavigationApplication read GetApplication; default;
    procedure AutoDetect(Recommended: TAHMNavigationApplication);
    function FindApplication(ApplicationName: String): TAHMNavigationApplication;
  end;

  TAHMNavigationManager = class(TPersistent)
  private
    FFilename: String;
    FMediate: IMediateServer;
    FApplication: TAHMNavigationApplication;
    FApplications: TAHMNavigationApplications;
  protected
    procedure LogMessage(Level: LoggingLevel; LogMessage: String);
  public
    constructor Create(Server: IMediateServer);
    destructor Destroy; override;
    property Applications: TAHMNavigationApplications read FApplications;
    procedure Initialise;
    procedure Finalise;
    procedure Configure;
  published
    property Application: TAHMNavigationApplication read FApplication;
  end;


implementation

uses SysUtils, Registry, ConfigurationForm, PersistenceHelper, Utilities;

// TAHMNavigationApplication

procedure TAHMNavigationApplication.Clear;
begin
  FName := '';
  FReadOnly := False;
  FPath := '';
  FParameters := '';
  FWindowName := '';
  FWindowClass := '';
  FWindowLock := False;
end;

procedure TAHMNavigationApplication.Assign(Source: TPersistent);
begin
  if (Source is TAHMNavigationApplication) and (Source <> Self) then
  begin
    FName := TAHMNavigationApplication(Source).Name;
    FReadOnly := TAHMNavigationApplication(Source).ReadOnly;
    FPath := TAHMNavigationApplication(Source).Path;
    FParameters := TAHMNavigationApplication(Source).Parameters;
    FWindowName := TAHMNavigationApplication(Source).WindowName;
    FWindowClass := TAHMNavigationApplication(Source).WindowClass;
    FWindowLock := TAHMNavigationApplication(Source).WindowLock;
  end;
end;

// TAHMNavigationApplications

constructor TAHMNavigationApplications.Create;
begin
  inherited;

  FList := TList.Create;
end;

destructor TAHMNavigationApplications.Destroy;
begin
  Clear;
  FList.Free;

  inherited;
end;

function TAHMNavigationApplications.GetCount: Integer;
begin
  Result := FList.Count;
end;

function TAHMNavigationApplications.GetApplication(Index: Integer): TAHMNavigationApplication;
begin
  if (Index >= 0) and (Index < FList.Count) then
    Result := TAHMNavigationApplication(FList[Index])
  else
    Result := nil;
end;

function TAHMNavigationApplications.AddApplication(Name, Path, WindowName, WindowClass: WideString; WindowLock: Boolean): TAHMNavigationApplication;
begin
  Result := TAHMNavigationApplication.Create;
  Result.Name := Name;
  Result.Path := Path;
  Result.WindowName := WindowName;
  Result.WindowClass := WindowClass;
  Result.WindowLock := WindowLock;
  Result.ReadOnly := True;
  FList.Add(Result);
end;

procedure TAHMNavigationApplications.Clear;
var
  i: Integer;
begin
  for i := 0 to Pred(FList.Count) do
    TAHMNavigationApplication(FList[i]).Free;

  FList.Clear;
end;

procedure TAHMNavigationApplications.AutoDetect(Recommended: TAHMNavigationApplication);
var
  Reg: TRegistry;
  Work: String;
  BestFit: TAHMNavigationApplication;
begin
  // First populate 'custom' navigation application instance
  Clear;
  BestFit := AddApplication(APP_CUSTOM, '', '', '', False);
  BestFit.ReadOnly := False;

  Reg := TRegistry.Create(KEY_READ);
  try
    Reg.RootKey := HKEY_LOCAL_MACHINE;

    // Look for iGuidance version 3.0
    if Reg.OpenKeyReadOnly('\SOFTWARE\iNav\iGuidance\3.0') then
    begin
      Work := GetWindowsPath(wpProgramFiles) + '\iNav\iGuidancce\iGuidanceUMPC.exe';
      BestFit := AddApplication(APP_IGUIDE3, Work, 'iGuidance', 'IntellinavWCls', False);
    end;

    // Look for PC Navigator version 6
    if Reg.OpenKeyReadOnly('\SOFTWARE\MapFactor\set\pcnavigator_6') then
    begin
      Work := Reg.ReadString('Atlas');
      Work := ParentFolder(ExtractFilePath(Work)) + 'PC_Navigator.exe';
      BestFit := AddApplication(APP_PC_NAV6, Work, 'Navigator 6', '', False);
    end;

    // Look for PC Navigator version 7
//TODO: untested!
    if Reg.OpenKeyReadOnly('\SOFTWARE\MapFactor\set\pcnavigator_7') then
    begin
      Work := Reg.ReadString('Atlas');
      Work := ParentFolder(ExtractFilePath(Work)) + 'PC_Navigator.exe';
      BestFit := AddApplication(APP_PC_NAV7, Work, 'Navigator 7', '', False);
    end;

  finally
    Reg.Free;
  end;

  // If current recommendation empty then overwrite it with best match
  if Recommended.Name = '' then
    Recommended.Assign(BestFit);
end;

function TAHMNavigationApplications.FindApplication(ApplicationName: String): TAHMNavigationApplication;
var
  i: Integer;
begin
  // Set default result - none found
  Result := nil;

  for i := 0 to Pred(FList.Count) do
    if TAHMNavigationApplication(FList[i]).Name = ApplicationName then
    begin
      Result := TAHMNavigationApplication(FList[i]);
      Break;
    end;
end;

// TAHMNavigationManager

constructor TAHMNavigationManager.Create(Server: IMediateServer);
var
  ConfigDir: WideString;
begin
  inherited Create;

  // Store server instance & build persistence filename
  FMediate := Server;
  Server.GetConfigDirectory(ConfigDir);
  FFilename := ConfigDir + FILE_NAVIGATION;

  FApplications := TAHMNavigationApplications.Create;
  FApplication := TAHMNavigationApplication.Create;

  // Load configuration settings, then autoconfigure
  TAHMPersistenceHelper.LoadObject(Self, FFilename);
  FApplications.AutoDetect(FApplication);

  LogMessage(llDebug, 'loaded plugin successfully');
end;

destructor TAHMNavigationManager.Destroy;
begin
  FApplications.Free;
  FApplication.Free;
  LogMessage(llDebug, 'unloaded plugin successfully');

  inherited;
end;

procedure TAHMNavigationManager.Initialise;
var
  Running: WordBool;
begin
  with FMediate as IMediateApplication do
  begin
    // Launch navigation application if required and not already running
    if FApplication.Path <> '' then
      if IsRunning(FApplication.Path, Running) = S_OK then
        if not Running then
        begin
          LogMessage(llDebug, 'launching navigation application: ' + FApplication.Path);
          LaunchApplication(FApplication.Path, FApplication.Parameters);
        end;

    // Embed application if required
    if (FApplication.WindowName <> '') or (FApplication.WindowClass <> '') then
    begin
      LogMessage(llDebug, 'embedding navigation window: ' + FApplication.WindowName +
                          '(' + FApplication.WindowClass + ')');
      EmbedApplication(FApplication.WindowName, FApplication.WindowClass, FApplication.WindowLock);
    end;
  end;
end;

procedure TAHMNavigationManager.Finalise;
begin
  with FMediate as IMediateApplication do
  begin
    // Close navigation application if required
    if FApplication.Path <> '' then
    begin
      LogMessage(llDebug, 'closing navigation application: ' + FApplication.Path);
      CloseApplication(FApplication.Path);
    end;
  end;
end;

procedure TAHMNavigationManager.LogMessage(Level: LoggingLevel; LogMessage: String);
begin
  FMediate.LogMessage(Level, LogMessage);
end;

procedure TAHMNavigationManager.Configure;
begin
  // Launch configuration form & save changes if required
  if TfrmNavigationConfig.Configure(Self) then
  begin
    LogMessage(llDebug, 'updating navigation settings...');
    TAHMPersistenceHelper.SaveObject(Self, FFilename);
    LogMessage(llDebug, 'navigation settings updated');
  end;
end;


end.
